//
//  MACD.swift
//  GomroClient
//
//  Created by xiaogxjkz on 2021/4/15.
//  Copyright © 2021 cn.gomro.app. All rights reserved.
//

import Foundation

/// MACD 指数平滑移动平均线
/// 参考：https://blog.csdn.net/yuhk231/article/details/80810274
@objc public class MACD: NSObject {
    
    enum kpiType:String {
        case dif = "DIF"
        case dea = "DEA"
        case macd = "MACD"
    }
    
    /// 计算MACD
    /// - Parameters:
    ///   - d: 输入数据
    ///   - s: 快速EMA时间窗口 默认 12
    ///   - l: 慢速EMA时间窗口 默认 26
    ///   - m: mid 对dif的时间窗口 默认 9
    ///   - f: 计算字段
    /// - Returns: [Double]
    @objc public class func calcMACDFor(Data d:[[String:Any]],
                     andShort s:Int = 12,
                     andLong l:Int = 26,
                     andMid m:Int = 9,
                     withFiled f:String? = "Close") -> [String:[Double]] {
        
        let dif = calcDIFFor(Data: d,
                             andShort: s,
                             andLong: l,
                             withFiled: f)
        
        let dea = calcDEAFor(Data: dif,
                             andMid: m,
                             withFiled: nil)
        
        var macd = [Double]()
        for i in 0..<d.count {
            macd.append((dif[i] - dea[i]) * 2)
        }
        
        return [
            kpiType.dif.rawValue:dif,
            kpiType.dea.rawValue:dea,
            kpiType.macd.rawValue:macd,
        ]
    }
    
    
    /// - Parameters:
    ///   - d: 输入数据
    ///   - s: 快速EMA时间窗口 默认 12
    ///   - l: 慢速EMA时间窗口 默认 26
    ///   - m: mid 对dif的时间窗口 默认 9
    ///   - f: 计算字段
    /// - Returns: [Double]
    @objc public class func calcMACDFor(Model d:[GameMarketModel],
                     andShort s:Int = 12,
                     andLong l:Int = 26,
                     andMid m:Int = 9) -> [String:[Double]] {
        
        let dif = calcDIFFor(Model: d,
                             andShort: s,
                             andLong: l)
        
        let dea = calcDEAFor(Data: dif,
                             andMid: m,
                             withFiled: nil)
        
        var macd = [Double]()
        for i in 0..<d.count {
            macd.append((dif[i] - dea[i]) * 2)
        }
        
        return [
            kpiType.dif.rawValue:dif,
            kpiType.dea.rawValue:dea,
            kpiType.macd.rawValue:macd,
        ]
    }
}


//MARK: -
extension MACD {
    
    /// 计算EMA指数平滑移动平均线，用于MACD
    /// - Parameters:
    ///   - d: 输入数据
    ///   - n: 时间窗口
    ///   - f: 计算字段
    /// - Returns: [Double]
    private class func calcEMAFor(Data d:[Any],
                            andNmbner n:Int,
                            withFiled f:String? = "Close") -> [Double] {
        
        let a:Double = 2 / (Double(n) + 1)
        var emaArr = [Double](repeating: 0, count: d.count)
        
        if f != nil && f != "" {
            //复杂对象数组
            var dicTemp:[String:Any]? = d[0] as? [String:Any]
            if dicTemp == nil && d[0] is GameMarketModel {
                dicTemp = (d[0] as? GameMarketModel)?.modelToDictionary()
            }
            
            if let _dicTemp = dicTemp {
                emaArr[0] = Double(_dicTemp[f!] as? String ?? "1")!
                
                for i in 1..<d.count {
                    var _item:[String:Any]? = d[i] as? [String:Any]
                    if _item == nil && d[i] is GameMarketModel {
                        _item = (d[i] as? GameMarketModel)?.modelToDictionary()
                    }
                    
                    if let item = _item {
                        let _tempPre = a * Double(item[f!] as? String ?? "1")!
                        let _tempSuf = (1 - a) * emaArr[i - 1]
                        emaArr[i] = _tempPre + _tempSuf
                    }
                }
            }
        }
        else{
            emaArr[0] = Double("\(d[0])")!
            
            for i in 1..<d.count {
                let _tempPre = a * Double("\(d[i])")!
                let _tempSuf = (1 - a) * emaArr[i - 1]
                emaArr[i] = _tempPre + _tempSuf
            }
        }
        
        return emaArr
    }
    
    
    /// 计算DIF快线，用于MACD
    /// - Parameters:
    ///   - d: 输入数据
    ///   - s: 快速EMA时间窗口 默认 12
    ///   - l: 慢速EMA时间窗口 默认 26
    ///   - f: 计算字段
    /// - Returns: [Double]
    private class func calcDIFFor(Data d:[[String:Any]],
                            andShort s:Int,
                            andLong l:Int,
                            withFiled f:String? = "Close") -> [Double] {
        
        var dif = [Double]()
        let emaShort = calcEMAFor(Data: d, andNmbner: s, withFiled: f)
        let emaLong = calcEMAFor(Data: d, andNmbner: l, withFiled: f)
        
        for i in 0..<d.count {
            dif.append(emaShort[i] - emaLong[i])
        }
        
        return dif
    }
    
    private class func calcDIFFor(Model d:[GameMarketModel],
                            andShort s:Int,
                            andLong l:Int) -> [Double] {
        
        var dif = [Double]()
        let emaShort = calcEMAFor(Data: d, andNmbner: s, withFiled: "close")
        let emaLong = calcEMAFor(Data: d, andNmbner: l, withFiled: "close")
        
        for i in 0..<d.count {
            dif.append(emaShort[i] - emaLong[i])
        }
        
        return dif
    }
    
    
    /// 计算DEA慢线，用于MACD
    /// - Parameters:
    ///   - d: 输入数据
    ///   - m: mid 对dif的时间窗口 默认 9
    ///   - f: 计算字段
    /// - Returns: [Double]
    private class func calcDEAFor(Data d:[Any],
                            andMid m:Int,
                            withFiled f:String? = "Close") -> [Double] {
        return calcEMAFor(Data: d, andNmbner: m, withFiled: f)
    }
}
